home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
elv18src.zip
/
cut.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-02
|
16KB
|
777 lines
/* cut.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains function which manipulate the cut buffers. */
#include "config.h"
#include "vi.h"
#if TURBOC
#include <process.h> /* needed for getpid */
#endif
#if TOS
#include <osbind.h>
#define rename(a,b) Frename(0,a,b)
#endif
# define NANONS 9 /* number of anonymous buffers */
static struct cutbuf
{
short *phys; /* pointer to an array of #s of BLKs containing text */
int nblks; /* number of blocks in phys[] array */
int start; /* offset into first block of start of cut */
int end; /* offset into last block of end of cut */
int tmpnum; /* ID number of the temp file */
char lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */
}
named[27], /* cut buffers "a through "z and ". */
anon[NANONS]; /* anonymous cut buffers */
static char cbname; /* name chosen for next cut/paste operation */
static char dotcb; /* cut buffer to use if "doingdot" is set */
#ifndef NO_RECYCLE
/* This function builds a list of all blocks needed in the current tmp file
* for the contents of cut buffers.
* !!! WARNING: if you have more than ~450000 bytes of text in all of the
* cut buffers, then this will fail disastrously, because buffer overflow
* is *not* allowed for.
*/
int cutneeds(need)
BLK *need; /* this is where we deposit the list */
{
struct cutbuf *cb; /* used to count through cut buffers */
int i; /* used to count through blocks of a cut buffer */
int n; /* total number of blocks in list */
n = 0;
/* first the named buffers... */
for (cb = named; cb < &named[27]; cb++)
{
if (cb->tmpnum != tmpnum)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
/* then the anonymous buffers */
for (cb = anon; cb < &anon[NANONS]; cb++)
{
if (cb->tmpnum != tmpnum)
continue;
for (i = cb->nblks; i-- > 0; )
{
need->n[n++] = cb->phys[i];
}
}
/* return the length of the list */
return n;
}
#endif
static void maybezap(num)
int num; /* the tmpnum of the temporary file to [maybe] delete */
{
char cutfname[80];
int i;
/* if this is the current tmp file, then we'd better keep it! */
if (tmpfd >= 0 && num == tmpnum)
{
return;
}
/* see if anybody else needs this tmp file */
for (i = 27; --i >= 0; )
{
if (named[i].nblks > 0 && named[i].tmpnum == num)
{
break;
}
}
if (i < 0)
{
for (i = NANONS; --i >= 0 ; )
{
if (anon[i].nblks > 0 && anon[i].tmpnum == num)
{
break;
}
}
}
/* if nobody else needs it, then discard the tmp file */
if (i < 0)
{
#if MSDOS || TOS || OS2
strcpy(cutfname, o_directory);
if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i - 1]))
cutfname[i++] = SLASH;
sprintf(cutfname + i, TMPNAME + 3, getpid(), num);
#else
sprintf(cutfname, TMPNAME, o_directory, getpid(), num);
#endif
unlink(cutfname);
}
}
/* This function frees a cut buffer. If it was the last cut buffer that
* refered to an old temp file, then it will delete the temp file. */
static void cutfree(buf)
struct cutbuf *buf;
{
int num;
/* return immediately if the buffer is already empty */
if (buf->nblks <= 0)
{
return;
}
/* else free up stuff */
num = buf->tmpnum;
buf->nblks = 0;
#ifdef DEBUG
if (!buf->phys)
msg("cutfree() tried to free a NULL buf->phys pointer.");
else
#endif
_free_((char *)buf->phys);
/* maybe delete the temp file */
maybezap(num);
}
/* This function is called when we are about to abort a tmp file.
*
* To minimize the number of extra files lying around, only named cut buffers
* are preserved in a file switch; the anonymous buffers just go away.
*/
void cutswitch()
{
int i;
/* mark the current temp file as being "obsolete", and close it. */
storename((char *)0);
close(tmpfd);
tmpfd = -1;
/* discard all anonymous cut buffers */
for (i = 0; i < NANONS; i++)
{
cutfree(&anon[i]);
}
/* delete the temp file, if we don't really need it */
maybezap(tmpnum);
}
/* This function should be called just before termination of vi */
void cutend()
{
int i;
/* free the anonymous buffers, if they aren't already free */
cutswitch();
/* free all named cut buffers, since they might be forcing an older
* tmp file to be retained.
*/
for (i = 0; i < 27; i++)
{
cutfree(&named[i]);
}
/* delete the temp file */
maybezap(tmpnum);
}
/* This function is used to select the cut buffer to be used next */
void cutname(name)
int name; /* a single character */
{
cbname = name;
}
#ifndef NO_LEARN
/* This function appends a single character to a cut buffer; it is used
* during "learn" mode to record a keystroke. The buffer to use is determined
* by an external variable, `learnbuf'; this variable contains the buffer's
* name while learning, or '\0' if not learning.
*/
void learnkey(key)
char key; /* keystroke to append to learning buffer */
{
static char prevlearn; /* previously learned buffer name */
static char buf[BLKSIZE]; /* used for storing keystrokes */
static int nkeys; /* number of keystrokes in buf[] */
struct cutbuf *cb; /* ptr to buffer being saved */
long seekpos; /* where saved cutbuf's text goes */
/* if we're ending a learn operation, then save keystokes in a cutbuf */
if (learn != prevlearn && prevlearn)
{
/* choose the cutbuffer to use; free its old contents, if any */
cb = &named[prevlearn - 'a'];
cutfree(cb);
/* delete the final "]a" (or whatever) from the keystoke buffer */
nkeys -= 2;
/* allocate a BLK for storage of the keystrokes */
cb->phys = (short *)malloc(sizeof(short));
cb->nblks = 1;
cb->start = 0;
cb->end = nkeys;
cb->tmpnum = tmpnum;
#ifndef NO_RECYCLE
seekpos = allocate();
lseek(tmpfd, seekpos, 0);
#else
seekpos = lseek(tmpfd, 0L, 2);
#endif
cb->phys[0] = (short)(seekpos / BLKSIZE);
/* write the keystokes there */
if (write(tmpfd, buf, (unsigned)BLKSIZE) != BLKSIZE)
{
msg("Trouble writing to tmp file");
deathtrap(0);
}
/* saving complete */
prevlearn = '\0';
nkeys = 0;
}
/* if we're learning a buffer now, save the keystroke */
if (learn)
{
prevlearn = learn;
buf[nkeys++] = key;
if (nkeys >= BLKSIZE - 2)
{
msg("Learn buffer full");
learn = 0;
nkeys += 2; /* <- to fake "]a" in keystroke buffer */
}
}
}
#endif /* !NO_LEARN */
/* This function copies a selected segment of text to a cut buffer */
void cut(from, to)
MARK from; /* start of text to cut */
MARK to; /* end of text to cut */
{
int first; /* logical number of first block in cut */
int last; /* logical number of last block used in cut */
long line; /* a line number */
int lnmode; /* boolean: will this be a line-mode cut? */
MARK delthru;/* end of text temporarily inserted for apnd */
REG struct cutbuf *cb;
REG long l;
REG int i;
REG char *scan;
char *blkc;
/* detect whether this must be a line-mode cut or char-mode cut */
if (markidx(from) == 0 && markidx(to) == 0)
lnmode = TRUE;
else
lnmode = FALSE;
/* by default, we don't "delthru" anything */
delthru = MARK_UNSET;
/* handle the "doingdot" quirks */
if (doingdot)
{
if (!cbname)
{
cbname = dotcb;
}
}
else if (cbname != '.')
{
dotcb = cbname;
}
/* decide which cut buffer to use */
if (!cbname)
{
/* free up the last anonymous cut buffer */
cutfree(&anon[NANONS - 1]);
/* shift the anonymous cut buffers */
for (i = NANONS - 1; i > 0; i--)
{
anon[i] = anon[i - 1];
}
/* use the first anonymous cut buffer */
cb = anon;
cb->nblks = 0;
}
else if (cbname >= 'a' && cbname <= 'z')
{
cb = &named[cbname - 'a'];
cutfree(cb);
}
#ifndef CRUNCH
else if (cbname >= 'A' && cbname <= 'Z')
{
cb = &named[cbname - 'A'];
if (cb->nblks > 0)
{
/* resolve linemode/charmode differences */
if (!lnmode && cb->lnmode)
{
from &= ~(BLKSIZE - 1);
if (markidx(to) != 0 || to == from)
{
to = to + BLKSIZE - markidx(to);
}
lnmode = TRUE;
}
/* insert the old cut-buffer before the new text */
mark[28] = to;
delthru = paste(from, FALSE, TRUE);
if (delthru == MARK_UNSET)
{
return;
}
delthru++;
to = mark[28];
}